package com.longsichao.lscframe.ctrl;

import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.longsichao.lscframe.model.LSCModel;
import com.longsichao.lscframe.net.Api;
import com.longsichao.lscframe.tools.LSCLog;
import com.longsichao.lscframe.view.LSCToast;

import java.util.LinkedList;
import java.util.List;

/**
 * @author SONG GUANYULONGSICHAO (leo.song[at]outlook[dot]com)
 */
public final class DataManager implements Callback, CtrlConstants, CacheManager.OnCacheListener {

    private class DMData {
        private int mCaseId;
        private LSCModel.OnModelListener mListener;
        private int mRequestCode;
        private Api api;

        public DMData(Api api, LSCModel.OnModelListener l, int requestCode, int caseId) {
            this.api = api;
            this.mListener = l;
            this.mRequestCode = requestCode;
            this.mCaseId = caseId;
        }
    }

    private static int BASE_REQUEST_CODE = 0;

    private static DataManager mDataManager = null;

    /**
     * Get data from registered API.
     *
     * @param caseId For {@link LSCModel.OnModelListener OnModelListener}'s {@link LSCModel.OnModelListener#onModel(int, LSCModel) callback}, defined by this method caller.
     * @param l      Return data in this callback.
     * @return Return request code.
     */
    public static int getData(int caseId, Api api, LSCModel.OnModelListener l) {
        if (mDataManager == null) {
            mDataManager = new DataManager();
        }
        int requestCode = BASE_REQUEST_CODE++;
        DMData dMData = mDataManager.new DMData(api, l, requestCode, caseId);
        mDataManager.mDataList.add(dMData);
        Message msg = mDataManager.mHandler.obtainMessage(DM_MW_LOAD_DATA, dMData);
        mDataManager.mHandler.sendMessage(msg);
        return requestCode;
    }

    private List<DMData> mDataList = new LinkedList<>();

    private Handler mHandler = new Handler(this);

    private DataManager() {
    }

    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what) {
            case DM_MW_LOAD_DATA:
                DMData data = (DMData) msg.obj;
                CacheManager.getJson(data.mRequestCode, data.api, this);
                return true;
            default:
                return false;
        }
    }

    @Override
    public void onCache(int requestCode, String jsonString) {
        DMData data = getDMData(requestCode);
        if (data == null) {
            LSCLog.w("Data not found.");
            return;
        }
        if (jsonString == null) {
            data.mListener.onModel(data.mCaseId, null);
            return;
        }
        LSCLog.d(jsonString);
        LSCModel model = null;
        try {
            Class<? extends LSCModel> modelClass = data.api.getModelClass();
            if (modelClass == null) {
                LSCLog.e("Model class is null.");
            } else {
                if (isGoodJson(jsonString)){
                    Gson  gson=new GsonBuilder().serializeNulls().create();
                    model = gson.fromJson(jsonString, modelClass);
                }else{
                    LSCLog.e("Model class is error Json");
                }

            }
        } catch (Exception e) {
            LSCLog.e("Formatting json string to model error.", e);
        }
        data.mListener.onModel(data.mCaseId, model);
        removieDMData(requestCode);
    }

    private void removieDMData(int requestCode) {
        for (DMData data : mDataList) {
            if (data.mRequestCode == requestCode) {
                mDataList.remove(data);
                return;
            }
        }
    }

    private DMData getDMData(int requestCode) {
        for (DMData data : mDataList) {
            if (data.mRequestCode == requestCode) {
                return data;
            }
        }
        return null;
    }
    public static boolean isBadJson(String json) {
        return !isGoodJson(json);
    }

    public static boolean isGoodJson(String json) {
        if (json==null||json.equals("")||json.isEmpty()) {
            return false;
        }
        try {
            new JsonParser().parse(json);
            return true;
        } catch (JsonParseException e) {
            LSCLog.e("bad json: " + json);
            return false;
        }
    }
}
